﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Windows.Input;
using ScrumFactory.Composition;
using ScrumFactory.Composition.ViewModel;
using ScrumFactory.Services;
using ScrumFactory.Windows.Helpers;
using System.Linq;

namespace ScrumFactory.Backlog.ViewModel {
    
    [Export(typeof(IBurndownViewModel))]
    public class BurndownViewModel : BasePanelViewModel, IBurndownViewModel, INotifyPropertyChanged {

        private IBacklogService backlogService;
        private IBackgroundExecutor executor;
        private IEventAggregator aggregator;

        private ICollection<BurndownLeftHoursByDay> actualHours;
        private ICollection<BurndownLeftHoursByDay> actualHoursAhead;
        private ICollection<BurndownLeftHoursByDay> plannedHours;

        private BurndownPlanningCurves planningCurveMode;

        public Project Project { get; private set; }

        [ImportingConstructor()]
        public BurndownViewModel(
            [Import] IBacklogService backlogService,
            [Import] IBackgroundExecutor backgroundExecutor,
            [Import] IEventAggregator eventAggregator) {

            this.backlogService = backlogService;
            this.executor = backgroundExecutor;
            this.aggregator = eventAggregator;

            NeedRefresh = false;
            OnLoadCommand = new DelegateCommand(
                () => {
                    if (NeedRefresh) LoadData();
                });

            ChangePlanningCurveCommand = new DelegateCommand<string>(
                mode => {
                    PlanningCurveMode = (BurndownPlanningCurves) Enum.Parse(typeof(BurndownPlanningCurves), mode);
                });
                    

        
            aggregator.Subscribe<Project>(ScrumFactoryEvent.ViewProjectDetails, OnViewProjectDetails);
            aggregator.Subscribe<object[]>(ScrumFactoryEvent.BacklogItemMoved, o => { AskForRefresh(); });
            aggregator.Subscribe<ICollection<Sprint>>(ScrumFactoryEvent.SprintsDateChanged, o => { AskForRefresh(); });

        }

        public bool IsVisible {
            get {
                return View.IsVisible;
            }            
        }

        private void AskForRefresh() {
            if (IsVisible)
                LoadData();
            else
                NeedRefresh = true;            
        }

        private void OnViewProjectDetails(Project project) {
            Project = project;
            AskForRefresh();            
        }

        private void LoadData() {                        
            IsLoadingData = true;
            executor.StartBackgroundTask<ICollection<BurndownLeftHoursByDay>>(LoadCurveData, OnDataLoaded);
        }

        private ICollection<BurndownLeftHoursByDay> LoadCurveData() {
            if(PlanningCurveMode==BurndownPlanningCurves.FIRST_PLANNING)
                return backlogService.GetBurndownHoursByDayFirstPlanning(Project.ProjectUId);
            if(PlanningCurveMode==BurndownPlanningCurves.PROPOSAL_PLANNING)
                return backlogService.GetBurndownHoursByDayProposalPlanning(Project.ProjectUId);

            return backlogService.GetBurndownHoursByDay(Project.ProjectUId);

        }

        private void OnDataLoaded(ICollection<BurndownLeftHoursByDay> leftHoursByDay) {
            IsLoadingData = false;
            NeedRefresh = false;
            ActualHours = leftHoursByDay.Where(h => h.LeftHoursMetric==LeftHoursMetrics.LEFT_HOURS).ToArray();
            ActualHoursAhead = leftHoursByDay.Where(h => h.LeftHoursMetric == LeftHoursMetrics.LEFT_HOURS_AHEAD).ToArray();
            PlannedHours = leftHoursByDay.Where(h => h.LeftHoursMetric == LeftHoursMetrics.PLANNING).ToArray();            
        }

        /// <summary>
        /// Gets or sets the view.
        /// </summary>
        /// <value>The view.</value>
        [Import(typeof(IBurndownView))]
        public IBurndownView View { get; set; }


        #region IBurndownViewModel Members


        object IBurndownViewModel.View {
            get {
                return this.View;
            }
        }

        public BurndownPlanningCurves PlanningCurveMode {
            get {
                return planningCurveMode;
            }
            set {
                planningCurveMode = value;
                OnPropertyChanged("PlanningCurveMode");
                LoadData();
            }
        }
     
        public ICollection<BurndownLeftHoursByDay> PlannedHours {
            get {
                return plannedHours;
            }
            set {
                plannedHours = value;
                OnPropertyChanged("PlannedHours");
            }
        }

        public ICollection<BurndownLeftHoursByDay> ActualHours {
            get {
                return actualHours;
            }
            set {
                actualHours = value;
                OnPropertyChanged("ActualHours");
            }
        }

        public ICollection<BurndownLeftHoursByDay> ActualHoursAhead {
            get {
                return actualHoursAhead;
            }
            set {
                actualHoursAhead = value;
                OnPropertyChanged("ActualHoursAhead");
            }
        }

        public ICommand OnLoadCommand { get; private set; }

        public ICommand ChangePlanningCurveCommand { get; private set; }

        #endregion
    }
}
